package org.jinyan.unused.socket;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

public class EchoTestClient {

	private static int SOCKET_NUM = 55555;

	private static DateFormat dateFormatter = new SimpleDateFormat(
			"yyyyMMdd HH:mm:ss");

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		new EchoTestClient().start();
	}

	private void start() {
		SocketChannel client = null;
		try {
			Selector selector = Selector.open(); // 定义一个记录套接字通道事件的对象

			client = connect(selector);

			String a = "ABCD"; // 要发送的数据

			while (true) {
				ByteBuffer sendbuffer = ByteBuffer.allocate(40); // 定义用来存储发送数据的byte缓冲区

				ByteBuffer readBuffer = ByteBuffer.allocate(40); // 定义用于接收服务器返回的数据的缓冲区

				sendbuffer.put(a.getBytes()); // 将数据put进缓冲区

				sendbuffer.flip(); // 将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位

				client.write(sendbuffer); // 向服务器发送数据

				log("Send to server: " + new String(sendbuffer.array()));

				// 利用循环来读取服务器发回的数据
				{
					// 如果客户端连接没有打开就退出循环
					if (!client.isOpen())
						break;
					// 此方法为查询是否有事件发生如果没有就阻塞,有的话返回事件数量
					int shijian = selector.select(1000);
					// 如果没有事件返回循环
					if (shijian == 0) {
						continue;
					}
					// 定义一个临时的客户端socket对象
					SocketChannel sc;
					// 遍例所有的事件
					for (SelectionKey key : selector.selectedKeys()) {
						// 删除本次事件
						selector.selectedKeys().remove(key);
						// 如果本事件的类型为read时,表示服务器向本客户端发送了数据
						if (key.isReadable()) {
							// 将临时客户端对象实例为本事件的socket对象
							sc = (SocketChannel) key.channel();
							// 定义一个用于存储所有服务器发送过来的数据
							ByteArrayOutputStream bos = new ByteArrayOutputStream();
							// 将缓冲区清空以备下次读取
							readBuffer.clear();
							// 此循环从本事件的客户端对象读取服务器发送来的数据到缓冲区中
							while (sc.read(readBuffer) > 0) {
								// 将本次读取的数据存到byte流中
								bos.write(readBuffer.array());
								// 将缓冲区清空以备下次读取
								readBuffer.clear();
							}
							// 如果byte流中存有数据
							if (bos.size() > 0) {
								// 建立一个普通字节数组存取缓冲区的数据
								byte[] b = bos.toByteArray();

								log("Recive from server: " + new String(b));
							}
						}
					}
				}
				Thread.sleep(2000);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 关闭客户端连接,此时服务器在read读取客户端信息的时候会返回-1
			if (client != null) {
				try {
					client.close();
				} catch (IOException e) {
				}
				log("Connection closed!");
			}
		}
	}

	private SocketChannel connect(Selector selector) throws IOException {

		SocketAddress address = new InetSocketAddress("localhost", SOCKET_NUM); // 定义一个服务器地址的对象

		SocketChannel client = SocketChannel.open(address); // 定义异步客户端

		client.configureBlocking(false); // 将客户端设定为异步

		client.register(selector, SelectionKey.OP_READ); // 在轮讯对象中注册此客户端的读取事件(就是当服务器向此客户端发送数据的时候)

		return client;
	}

	private static void log(Object msg) {
		System.out.println("CLIENT [" + dateFormatter.format(new Date())
				+ "]: " + msg);
	}
}